/*
 * Copyright 2009 Pierre-Laurent Coirier
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package com.mvc4g.util;

import java.util.Iterator;

import org.apache.commons.configuration.ConfigurationException;
import org.apache.commons.configuration.HierarchicalConfiguration;
import org.apache.commons.configuration.XMLConfiguration;

import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.UnableToCompleteException;
import com.google.gwt.user.rebind.SourceWriter;

/**
 * This class reads the mvc4g-conf.xml
 * 
 * @author plcoirier
 * 
 */
public class Mvc4gConfigurationFileReader {

	private static String SPACE = " ";
	private static String EQUALS_NEW = " = new ";
	private static String COMA_NEW = "\", new ";
	private static String CLOSE_BRACKET = ");";
	private static String NO_ARGUMENT = "();";
	private static String DOUBLE_NO_ARGUMENT = "());";

	private SourceWriter sourceWriter = null;
	private TreeLogger logger = null;

	/**
	 * Create a Mvc4gConfigurationFileReader object
	 * 
	 * @param sourceWriter
	 * @param logger
	 */
	public Mvc4gConfigurationFileReader(SourceWriter sourceWriter,
			TreeLogger logger) {
		this.sourceWriter = sourceWriter;
		this.logger = logger;
	}

	/**
	 * Parses the mvc4g-conf.xml and write the information in the source writer
	 * 
	 * @throws UnableToCompleteException
	 *             exception thrown if the configuratin file is not correct
	 */
	@SuppressWarnings("unchecked")
	public void writeConf() throws UnableToCompleteException {
		try {
			XMLConfiguration xmlConfig = new XMLConfiguration("mvc4g-conf.xml");
			sendErrorIfNull(xmlConfig, "mvc4g-conf.xml is missing");

			Iterator<HierarchicalConfiguration> controllerIt = xmlConfig
					.configurationsAt("controller").iterator();

			Iterator<HierarchicalConfiguration> actionIt = null;
			Iterator<HierarchicalConfiguration> viewIt = null;

			HierarchicalConfiguration controllerConfig = null;
			HierarchicalConfiguration actionConfig = null;
			HierarchicalConfiguration viewConfig = null;

			String controllerName = null;
			String controllerClass = null;
			String parent = null;

			String viewName = null;
			String viewClass = null;

			String actionName = null;
			String actionClass = null;

			// TODO: use a string builder?
			while (controllerIt.hasNext()) {
				controllerConfig = controllerIt.next();
				controllerName = controllerConfig.getString("[@name]");
				sendErrorIfNull(controllerName, "Controller name is missing");

				controllerClass = controllerConfig.getString("[@class]");
				sendErrorIfNull(controllerClass, controllerName
						+ ": class is missing");

				parent = controllerConfig.getString("[@parent]");

				sourceWriter.print(controllerClass);
				sourceWriter.print(SPACE);
				sourceWriter.print(controllerName);
				sourceWriter.print(EQUALS_NEW);
				sourceWriter.print(controllerClass);
				sourceWriter.println(NO_ARGUMENT);

				actionIt = controllerConfig.configurationsAt("actions.action")
						.iterator();
				while (actionIt.hasNext()) {
					actionConfig = actionIt.next();
					actionName = actionConfig.getString("[@name]");
					sendErrorIfNull(actionName, "Action name is missing");

					actionClass = actionConfig.getString("[@class]");
					sendErrorIfNull(actionClass, actionName
							+ ": Action class is missing");

					sourceWriter.print(controllerName);
					sourceWriter.print(".addAction(\"");
					sourceWriter.print(actionName);
					sourceWriter.print(COMA_NEW);
					sourceWriter.print(actionClass);
					sourceWriter.println(DOUBLE_NO_ARGUMENT);

				}

				viewIt = controllerConfig.configurationsAt("views.view")
						.iterator();
				while (viewIt.hasNext()) {
					viewConfig = viewIt.next();
					viewName = viewConfig.getString("[@name]");
					sendErrorIfNull(viewName, "View name is missing");
					viewClass = viewConfig.getString("[@class]");
					sendErrorIfNull(viewClass, viewName
							+ ": View class is missing");

					sourceWriter.print(controllerName);
					sourceWriter.print(".addView(\"");
					sourceWriter.print(viewName);
					sourceWriter.print(COMA_NEW);
					sourceWriter.print(viewClass);
					sourceWriter.println(DOUBLE_NO_ARGUMENT);
				}

				if ((parent != null) && (parent.length() > 0)) {
					sourceWriter.print(controllerName);
					sourceWriter.print(".setParent(");
					sourceWriter.print(parent);
					sourceWriter.println(CLOSE_BRACKET);
				}

			}

			Iterator<HierarchicalConfiguration> startIt = xmlConfig.configurationsAt("start").iterator();
			if (startIt.hasNext()) {
				HierarchicalConfiguration start = startIt.next();
				controllerName = start.getString("[@controllerName]");
				sendErrorIfNull(controllerName,
						"Start: Controller name is missing");
				actionName = start.getString("[@actionName]");
				sendErrorIfNull(actionName, "Start: Action name is missing");
				sourceWriter.print(controllerName);
				sourceWriter.print(".handleEvent(new Event(\"");
				sourceWriter.print(actionName);
				sourceWriter.print("\", null));");
			}

		} catch (ConfigurationException e) {
			logger.log(TreeLogger.ERROR, e.getMessage());
			throw new UnableToCompleteException();
		}

	}

	private void sendErrorIfNull(Object value, String message)
			throws UnableToCompleteException {
		if (value == null) {
			logger.log(TreeLogger.ERROR, message);
			throw new UnableToCompleteException();
		}
	}

}
